package com.yuanli.card.manage.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yuanli.card.authentication.service.ISysUserService;
import com.yuanli.card.bus.CardRange;
import com.yuanli.card.bus.GroupUserCombo;
import com.yuanli.card.enumeration.CardLogTypeEnum;
import com.yuanli.card.enumeration.CardPeriodEnum;
import com.yuanli.card.enumeration.OrderTypeEnum;
import com.yuanli.card.exception.ServiceException;
import com.yuanli.card.manage.service.*;
import com.yuanli.card.mapper.*;
import com.yuanli.card.pojo.*;
import com.yuanli.card.req.*;
import com.yuanli.card.utils.CommonUtil;
import com.yuanli.card.utils.DateUtils;
import com.yuanli.card.utils.ExcelTileFiledIndex;
import com.yuanli.card.utils.ExcelUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Service
public class CardServiceImpl implements CardService {

    @Resource
    private CardMapper cardMapper;
    @Resource
    private EnterStoreMapper enterStoreMapper;
    @Resource
    private OutStoreMapper outStoreMapper;
    @Resource
    private PoolMapper poolMapper;
    @Resource
    private CustomerFundMapper customerFundMapper;
    @Resource
    private CardLogMapper cardLogMapper;
    @Resource
    private CardOrderMapper cardOrderMapper;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ComboRateService comboRateService;
    @Resource
    private ComboService comboService;
    @Resource
    private ChannelInterfaceService channelInterfaceService;
    @Resource
    private CardFreshService cardFreshService;


    @Override
    public Card getByIccid(String iccid) {
        return cardMapper.getByIccid(iccid);
    }

    @Override
    public PageInfo<Card> query(CardQueryReq req) {
        PageHelper.startPage(req.getPage(), req.getSize(), "id asc");
        return cardMapper.query(req).toPageInfo();
    }

    @Override
    public PageInfo<Map<String, Object>> operatingQuery(CardOperatingQueryReq req) {
        PageHelper.startPage(req.getPage(), req.getSize(), "id asc");
        return cardMapper.operatingQuery(req).toPageInfo();
    }

    @Override
    public PageInfo<Card> operateQuery(CardOperateQueryReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        return this.query(cardQueryReq);
    }

    @Override
    public List<Card> importQuery(List<Card> cardList, CardOperateExportReq req) {
        Integer page = req.getPage();
        Integer size = req.getSize();
        int begin = (page - 1) * size;
        int end = page * size - 1;
        if (cardList.size() <= end) {
            end = cardList.size() - 1;
        }
        int beginId = cardList.get(begin).getId();
        int endId = cardList.get(end).getId();
        return cardMapper.importQuery(beginId, endId);
    }

    /**
     * 入库
     *
     * @param req
     */
    @Override
    @Transactional
    public void enter(CardEnterReq req) {
        List<Card> cardList = this.excelToCardList(req.getFile());
        if (cardList == null || cardList.isEmpty()) {
            throw new ServiceException(1, "入库的卡信息为空");
        }
        /*List<String> iccidList = cardList.stream().map(Card::getIccid).collect(Collectors.toList());
        Map<String, CardPeriodEnum> periodEnumMap = channelInterfaceService.batchQueryCardLifeCycle(iccidList,req.getChannelCode());
        if (periodEnumMap == null || periodEnumMap.isEmpty() || periodEnumMap.size() != iccidList.size()) {
            throw new ServiceException("获取卡生命期-通道接口异常");
        }*/
        //todo 获取卡基本信息 生命期和开户时间
        Integer customerId = req.getCustomerId();
        String channelCode = req.getChannelCode();
        String comboCode = req.getComboCode();
        String poolCode = CommonUtil.randomCode();
        if (req.getShare() == 1) { // 流量共享 创建流量池
            Pool pool = new Pool();
            pool.setChannelCode(channelCode);
            pool.setComboCode(comboCode);
            pool.setPoolNo(cardList.get(0).getIccid());
            pool.setPoolCode(poolCode);
            pool.setPoolName("流量池" + poolCode);
            pool.setCustomerId(customerId);
            pool.setCreateTime(new Date());
            poolMapper.save(pool); //创建流量池
        }
        cardList.forEach(card -> {
            card.setChannelCode(channelCode);
            if (req.getShare() == 1) {
                card.setPoolCode(poolCode);
            }
            card.setComboCode(comboCode);
            card.setCustomerId(customerId);
            CardPeriodEnum periodEnum = CardPeriodEnum.test;
            card.setPeriod(periodEnum.name());
            card.setRealPeriod(periodEnum.name());
            card.setCloseStatus(0);
            card.setCreateTime(new Date());
            card.setEnterTime(new Date());
        });
        cardMapper.batchSave(cardList); //批量保存卡信息
        int maxId = cardMapper.getMaxId();

        EnterStore enterStore = new EnterStore();
        enterStore.setCreateTime(new Date());
        enterStore.setCardNum(cardList.size());
        enterStore.setChannelCode(channelCode);
        enterStore.setComboCode(comboCode);
        enterStore.setBeginId(maxId - cardList.size() + 1);
        enterStore.setEndId(maxId);
        enterStore.setCustomerId(customerId);
        enterStoreMapper.save(enterStore);//保存入库记录
    }


    /**
     * 出售
     *
     * @param req
     * @return
     */
    @Override
    @Transactional
    public void sale(CardSaleReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        Integer countSale = cardMapper.count(cardQueryReq);
        if (countSale <= 0) {
            throw new ServiceException(1, "选择的卡数量为0，请重新选择");
        }
        CardRange cardRange = cardMapper.countCardRange(cardQueryReq);
        int beginId = cardRange.getBeginId();
        int endId = cardRange.getEndId();
        if (countSale != endId - beginId + 1) {
            throw new ServiceException(1, "卡id必须连续,请重新选择");
        }
        ComboRate comboRate = comboRateService.getByComboAndCustomer(req.getComboCode(), req.getSaleCustomerId());
        if (comboRate == null) {
            throw new ServiceException(1, "请先为出售客户添加套餐费率");
        }
        BigDecimal salePrice = comboRate.getSalePrice();//判断出售客户是否已创建费率 查询出售价格
        BigDecimal costPrice = comboRateService.getByComboAndCustomer(req.getComboCode(), req.getCustomerId()).getSalePrice();
        String comboCode = req.getComboCode();
        Card card = cardMapper.getById(beginId);
        String poolCode = card.getPoolCode();
        String channelCode = card.getChannelCode();

        cardMapper.updateBySale(cardQueryReq, req.getSaleCustomerId(), new Date());//修改卡所属客户
        poolMapper.updatePoolCustomer(poolCode, req.getSaleCustomerId());//修改流量池客户id

        OutStore outStore = new OutStore();
        SysUser saleUser = sysUserService.findById(req.getSaleCustomerId().longValue());
        outStore.setAddress(saleUser.getAddress());
        outStore.setCardNum(countSale);
        outStore.setCreateTime(new Date());
        outStore.setBeginId(beginId);
        outStore.setEndId(endId);
        outStore.setCustomerId(req.getCustomerId());
        outStore.setSaleCustomerId(req.getSaleCustomerId());
        outStore.setStatus(0); //未发货
        outStoreMapper.save(outStore);//保存平台出库记录

        EnterStore enterStore = new EnterStore();
        enterStore.setCustomerId(req.getSaleCustomerId());
        enterStore.setBeginId(beginId);
        enterStore.setEndId(endId);
        enterStore.setCardNum(countSale);
        enterStore.setComboCode(comboCode);
        enterStore.setChannelCode(channelCode);
        enterStore.setCreateTime(new Date());
        enterStoreMapper.save(enterStore);//保存客户入库记录

        CustomerFund customerFund = new CustomerFund();
        customerFund.setAmount(salePrice.multiply(new BigDecimal(countSale)).setScale(2, BigDecimal.ROUND_HALF_UP));
        customerFund.setCreateTime(new Date());
        customerFund.setCustomerId(req.getSaleCustomerId());
        customerFund.setRemark("入库扣款");
        customerFund.setType(2);
        customerFundMapper.save(customerFund);//保存客户扣款流水


        CardOrder cardOrder = new CardOrder();
        cardOrder.setChannelCode(channelCode);
        cardOrder.setComboCode(comboCode);
        cardOrder.setComboCost(costPrice); // 成本
        cardOrder.setComboPrice(salePrice); //售价
        cardOrder.setCardNum(countSale);
        cardOrder.setAmount(salePrice.multiply(new BigDecimal(countSale)).setScale(2, BigDecimal.ROUND_HALF_UP));
        cardOrder.setProfit(salePrice.subtract(costPrice).multiply(new BigDecimal(countSale)).setScale(2, BigDecimal.ROUND_HALF_UP));
        cardOrder.setCustomerId(req.getCustomerId());
        cardOrder.setSaleCustomerId(req.getSaleCustomerId());
        cardOrder.setCreateTime(new Date());
        cardOrder.setOrderNo(CommonUtil.randomCode());
        cardOrder.setType(OrderTypeEnum.sale.name());
        cardOrderMapper.save(cardOrder); //  保存平台订单

        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setCreateTime(new Date());
        cardLog.setOperateCustomerId(req.getCustomerId());
        cardLog.setType(CardLogTypeEnum.sale.name());
        cardLog.setStatus(0);
        cardLogMapper.save(cardLog);//保存操作日志
    }

    /**
     * 停机
     *
     * @param req
     * @return
     */
    @Override
    @Transactional
    public void stop(CardOperateQueryReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        Integer countSale = cardMapper.count(cardQueryReq);
        if (countSale <= 0) {
            throw new ServiceException(1, "选择的卡数量为0，请重新选择");
        }
        CardRange cardRange = cardMapper.countCardRange(cardQueryReq);
        int beginId = cardRange.getBeginId();
        int endId = cardRange.getEndId();
        if (countSale != endId - beginId + 1) {
            throw new ServiceException(1, "卡id必须连续,请重新选择");
        }

        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setCreateTime(new Date());
        cardLog.setOperateCustomerId(req.getCustomerId());
        cardLog.setType(CardLogTypeEnum.stop.name());
        cardLog.setStatus(1);
        cardLogMapper.save(cardLog);//保存操作日志
        cardMapper.updateByStop(cardQueryReq, cardLog.getId(), new Date()); //批量更新卡状态

        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
//            channelInterfaceService.batchStopOpen(cardMapper.queryIccidList(cardQueryReq), "StopSubs", "01", cardLog.getId());// 调停机接口
            //todo 批量停机之后调生命期更新接口 无论失败成功修改操作日志状态
        });
        executor.shutdown();
    }

    @Override
    @Transactional
    public void open(CardOperateQueryReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        Integer countSale = cardMapper.count(cardQueryReq);
        if (countSale <= 0) {
            throw new ServiceException(1, "选择的卡数量为0，请重新选择");
        }
        CardRange cardRange = cardMapper.countCardRange(cardQueryReq);
        int beginId = cardRange.getBeginId();
        int endId = cardRange.getEndId();
        if (countSale != endId - beginId + 1) {
            throw new ServiceException(1, "卡id必须连续,请重新选择");
        }
        Card beginCard = cardMapper.getById(beginId);
        Card endCard = cardMapper.getById(endId);
        if (beginCard.getCardLogId() != endCard.getCardLogId()) {
            throw new ServiceException(1, "只能复机同一批次停机的卡，请重新选择");
        }

        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setCreateTime(new Date());
        cardLog.setOperateCustomerId(req.getCustomerId());
        cardLog.setType(CardLogTypeEnum.open.name());
        cardLog.setStatus(1);
        cardLogMapper.save(cardLog);//保存操作日志
        cardMapper.updateByOpen(cardQueryReq, cardLog.getId(), new Date());//更新卡状态
        if (!DateUtils.format(new Date(), "yyyyMMdd").equals(DateUtils.format(beginCard.getCloseTime(), "yyyyMMdd"))) {//次月复机 扣费
            this.levelOrder(req.getCustomerId(), req.getComboCode(), countSale);
        }

        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            //channelInterfaceService.batchStopOpen(cardMapper.queryIccidList(cardQueryReq), "OpenSubs", "01", cardLog.getId());// 调复机接口
            //todo 批量开机之后调生命期更新接口 无论失败成功修改操作日志状态
        });
        executor.shutdown();
    }

    @Override
    @Transactional
    public void cancel(CardOperateQueryReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        Integer countSale = cardMapper.count(cardQueryReq);
        if (countSale <= 0) {
            throw new ServiceException(1, "选择的卡数量为0，请重新选择");
        }
        CardRange cardRange = cardMapper.countCardRange(cardQueryReq);
        int beginId = cardRange.getBeginId();
        int endId = cardRange.getEndId();
        if (countSale != endId - beginId + 1) {
            throw new ServiceException(1, "卡id必须连续,请重新选择");
        }
        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setCreateTime(new Date());
        cardLog.setOperateCustomerId(req.getCustomerId());
        cardLog.setType(CardLogTypeEnum.cancel.name());
        cardLog.setStatus(1);
        cardLogMapper.save(cardLog);//保存操作日志
        cardMapper.updateByCancel(cardQueryReq, cardLog.getId());//更新卡状态

        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            //channelInterfaceService.cancelTestPeriod(cardMapper.queryIccidList(cardQueryReq), cardLog.getId());
            //todo 批量开机之后调取消测试期接口 无论失败成功修改操作日志状态
        });
        executor.shutdown();
    }

    @Override
    public List<Card> export(CardOperateQueryReq req) {
        CardQueryReq cardQueryReq = this.transferOperateQuery(req);
        Integer countSale = cardMapper.count(cardQueryReq);
        if (countSale <= 0) {
            throw new ServiceException(1, "选择的卡数量为0，请重新选择");
        }
        CardRange cardRange = cardMapper.countCardRange(cardQueryReq);
        int beginId = cardRange.getBeginId();
        int endId = cardRange.getEndId();
        if (countSale != endId - beginId + 1) {
            throw new ServiceException(1, "卡id必须连续,请重新选择");
        }
        return cardMapper.queryAll(cardQueryReq);
    }


    @Override
    @Transactional
    public void preclose(List<Card> cardList) {
        int beginId = cardList.get(0).getId();
        int endId = cardList.get(cardList.size() - 1).getId();
        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setOperateCustomerId(sysUserService.currentUser().getId().intValue());
        cardLog.setCreateTime(new Date());
        cardLog.setType(CardLogTypeEnum.preclose.name());
        cardLog.setStatus(1);
        cardLogMapper.save(cardLog);//保存操作日志
        cardMapper.updateByClose(beginId, endId, cardLog.getId());

        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            try {
                cardFreshService.cardPeriodFresh(cardList.stream().map(card -> card.getIccid()).collect(Collectors.toList()), 0);// 调接口同步卡状态 异步
            } catch (Exception e) {
                //todo 记录异常
            } finally {
                cardLogMapper.updateStatus(cardLog.getId());
            }
        });
        executor.shutdown();
    }

    @Override
    @Transactional
    public void flowShare(List<Card> cardList) {
        int beginId = cardList.get(0).getId();
        int endId = cardList.get(cardList.size() - 1).getId();
        Card card = cardMapper.getById(beginId);
        if (card == null) {
            throw new ServiceException("找不到id=" + beginId + "的卡");
        }
        String poolCode = CommonUtil.randomCode();
        Pool pool = new Pool();
        pool.setChannelCode(card.getChannelCode());
        pool.setComboCode(card.getComboCode());
        pool.setPoolNo(card.getIccid());
        pool.setPoolCode(poolCode);
        pool.setPoolName("流量池" + poolCode);
        pool.setCustomerId(card.getCustomerId());
        pool.setCreateTime(new Date());
        poolMapper.save(pool); //创建流量池

        cardMapper.updatePoolCode(beginId, endId, poolCode);
        CardLog cardLog = new CardLog();
        cardLog.setBeginId(beginId);
        cardLog.setEndId(endId);
        cardLog.setOperateCustomerId(sysUserService.currentUser().getId().intValue());
        cardLog.setCreateTime(new Date());
        cardLog.setType(CardLogTypeEnum.flowshare.name());
        cardLog.setStatus(0);
        cardLogMapper.save(cardLog);//保存操作日志
    }

    @Override
    public void autoOrder() {
        List<GroupUserCombo> list = cardMapper.groupUserCombo();
        if (list == null || list.isEmpty()) {
            return;
        }
        list.forEach(groupUserCombo -> {
            this.levelOrder(groupUserCombo.getCustomerId(), groupUserCombo.getComboCode(), groupUserCombo.getNum());
        });
    }

    private CardQueryReq transferOperateQuery(CardOperateQueryReq req) {
        CardQueryReq queryParams = new CardQueryReq();
        queryParams.setCardCustomerId(req.getCustomerId()); // 查询库存
        queryParams.setPage(req.getPage());
        queryParams.setSize(req.getSize());
        queryParams.setBeginId(req.getBeginId());
        queryParams.setEndId(req.getEndId());
        queryParams.setComboCode(req.getComboCode());

        switch (req.getCardOperateType()) {
            case stop:
                // 未主动停机 正常卡
                queryParams.setCloseStatus(0);
                queryParams.setPeriod(CardPeriodEnum.normal.name());
                break;
            case open:
                //已主动停机 停机卡
                queryParams.setCloseStatus(1);
                queryParams.setPeriod(CardPeriodEnum.stop.name());
                break;
            case cancel:
                //测试期
                queryParams.setPeriod(CardPeriodEnum.test.name());
                break;
            default:
                queryParams.setValid(1);
                break;
        }
        return queryParams;
    }

    private void levelOrder(Integer customerId, String comboCode, Integer cardNum) {
        Long parentCustomerId = sysUserService.findById(customerId.longValue()).getParent_id();
        if (parentCustomerId == null) {//平台无上级 不产生订单
            return;
        }
        BigDecimal cost = comboRateService.getByComboAndCustomer(comboCode, parentCustomerId.intValue()).getSalePrice();// 根据parentCustomerId和comboCode获取成本
        BigDecimal price = comboRateService.getByComboAndCustomer(comboCode, customerId).getSalePrice();// 根据customerId和comboCode获取售价

        CustomerFund customerFund = new CustomerFund();
        customerFund.setAmount(price.multiply(new BigDecimal(cardNum)));
        customerFund.setCreateTime(new Date());
        customerFund.setCustomerId(customerId);
        customerFund.setRemark("复机扣款");
        customerFund.setType(2);
        customerFundMapper.save(customerFund);//保存客户扣款流水

        CardOrder cardOrder = new CardOrder();
        cardOrder.setChannelCode(comboService.getByComboNo(comboCode).getChannelNo());
        cardOrder.setComboCode(comboCode);
        cardOrder.setComboCost(cost); //成本
        cardOrder.setComboPrice(price); //售价
        cardOrder.setCardNum(cardNum);
        cardOrder.setAmount(price.multiply(new BigDecimal(cardNum)));
        cardOrder.setProfit(price.subtract(cost).multiply(new BigDecimal(cardNum)));
        cardOrder.setCustomerId(parentCustomerId.intValue());
        cardOrder.setSaleCustomerId(customerId);
        cardOrder.setCreateTime(new Date());
        cardOrder.setOrderNo(CommonUtil.randomCode());
        cardOrder.setType(OrderTypeEnum.open.name());
        cardOrderMapper.save(cardOrder); //  保存平台订单

        this.levelOrder(parentCustomerId.intValue(), comboCode, cardNum);
    }

    private List<Card> excelToCardList(MultipartFile file) {
        List<Card> result = null;
        ExcelTileFiledIndex filedIndex = new ExcelTileFiledIndex();
        filedIndex.addByAutoIndex("iccid", "iccid");
        try {
            result = ExcelUtils.excelToList(file.getInputStream(), 0, filedIndex, Card.class);
        } catch (IOException e) {
            throw new ServiceException("解析excel异常");
        }
        return result;
    }
}
